﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;



namespace Component
{
    public partial class UserChart : UserControl
    {
        int coordinateX;
        int coordinateY;
        int coordinateXSize;
        int coordinateYSize;

        Coordinate firstCoordinate;
        Coordinate secondCoordinate;
        Coordinate thirdCoordinate;


        protected override void OnPaint(PaintEventArgs e)
        {
            base.OnPaint(e);            
        }

        public void initUserChart()
        {

        }
        private SolidBrush defaultAuxiliaryAxisPointBrush;

        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public Coordinate FirstCoordinate { get => firstCoordinate; set => firstCoordinate = value; }
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public Coordinate SecondCoordinate { get => secondCoordinate; set => secondCoordinate = value; }
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public Coordinate ThirdCoordinate { get => thirdCoordinate; set => thirdCoordinate = value; }


        public void init()
        {
            Axis xAxis = new Axis();
            xAxis.MaxValue = 21.87 * 1.2;
            xAxis.MinValue = 0;
            xAxis.Name = "流量";

            //Coordinate.XAxis = xAxis;


            Axis yAxis = new Axis();
            yAxis.MaxValue = 765 * 1.2;
            yAxis.MinValue = 0;
            yAxis.Name = "扬程";

            firstCoordinate = new Coordinate();
            firstCoordinate.XAxis = xAxis;
            firstCoordinate.YAxis = yAxis;
            firstCoordinate.Points.Add(new Point(7.36, 765.51));
            firstCoordinate.Points.Add(new Point(8.65, 756.14));
            firstCoordinate.Points.Add(new Point(12.35, 715.11));
            firstCoordinate.Points.Add(new Point(13.08, 703.72));
            firstCoordinate.Points.Add(new Point(14.04, 689.42));
            firstCoordinate.Points.Add(new Point(16.09, 654.45));
            firstCoordinate.Points.Add(new Point(17.68, 621.62));
            firstCoordinate.Points.Add(new Point(19.35, 580.36));
            firstCoordinate.Points.Add(new Point(21.87, 512.58));
        

            Curve curve = new Curve(firstCoordinate.Points);
            firstCoordinate.Curves.Add(curve);

            SolidBrush solidBrush = new SolidBrush(Color.Red);
            firstCoordinate.CurvePen = new Pen(solidBrush, 3);

            SolidBrush pointBrush = new SolidBrush(Color.Orange);
            firstCoordinate.PointBrush = pointBrush;


            Axis ysecondAxis = new Axis();
            ysecondAxis.MaxValue = 4.8 * 1.2;
            ysecondAxis.MinValue = 0;
            ysecondAxis.Name = "功率";
            secondCoordinate = new Coordinate();
            secondCoordinate.YAxis = ysecondAxis;
            secondCoordinate.XAxis = xAxis;

            secondCoordinate.Points.Add(new Point(7.36, 3.11));
            secondCoordinate.Points.Add(new Point(8.65, 3.33));
            secondCoordinate.Points.Add(new Point(12.35, 3.73));
            secondCoordinate.Points.Add(new Point(13.08, 4.00));
            secondCoordinate.Points.Add(new Point(14.04, 4.02));
            secondCoordinate.Points.Add(new Point(16.09, 4.13));
            secondCoordinate.Points.Add(new Point(17.68, 4.35));
            secondCoordinate.Points.Add(new Point(19.35, 4.50));
            secondCoordinate.Points.Add(new Point(21.87, 4.63));

            Curve secondCurve = new Curve(secondCoordinate.Points);
            secondCoordinate.Curves.Add(secondCurve);


            Axis yThirddAxis = new Axis();
            yThirddAxis.MaxValue = 100;
            yThirddAxis.MinValue = 0;
            yThirddAxis.Name = "效率";
            ThirdCoordinate = new Coordinate();
            ThirdCoordinate.YAxis = yThirddAxis;
            ThirdCoordinate.XAxis = xAxis;

            ThirdCoordinate.Points.Add(new Point(7.36, 43.74));
            ThirdCoordinate.Points.Add(new Point(8.65, 47.42));
            ThirdCoordinate.Points.Add(new Point(12.35, 52.84));
            ThirdCoordinate.Points.Add(new Point(13.08, 53.39));
            ThirdCoordinate.Points.Add(new Point(14.04, 55.39));
            ThirdCoordinate.Points.Add(new Point(16.09, 56.67));
            ThirdCoordinate.Points.Add(new Point(17.68, 58.55));
            ThirdCoordinate.Points.Add(new Point(19.35, 58.97));
            ThirdCoordinate.Points.Add(new Point(21.87, 58.65));


            Curve thirdCurve = new Curve(ThirdCoordinate.Points);
            ThirdCoordinate.Curves.Add(thirdCurve);
        }

        public UserChart()
        {
            InitializeComponent();
            //init();
            initUserChart();
            //initPens();
        }


        /// <summary>
        /// 坐标轴转换，给一个坐标轴的数据，转成控件的位置
        /// </summary>
        /// <param name="coordinate"></param>
        /// <param name="data"></param>
        /// <returns></returns>
        private int[] transformsPoint(Coordinate coordinate, double[] data)
        {
         
            int y = -1 * (int)(this.coordinateYSize * data[1] / coordinate.YAxis.MaxValue) + this.coordinateY;
            int x = (int)(this.coordinateXSize * data[0] / coordinate.XAxis.MaxValue) + this.coordinateX;
            return new int[] { x, y };
        }

        private int[] transformsPoint(Coordinate coordinate, double[] data,Boolean log)
        {


            int y = -1 * (int)(this.coordinateYSize * data[1] / coordinate.YAxis.MaxValue) + this.coordinateY;
            int x = (int)(this.coordinateXSize * data[0] / coordinate.XAxis.MaxValue) + this.coordinateX;

            if (log)
            {
                System.Console.WriteLine(
                 "{0}:coordinateYSize={1},YAxis.MaxValue={2},coordinateY={3},coordinateXSize={4},XAxis.MaxValue={5},coordinateX={6},data[0]={7},data[1]={8},x={9},y={10}",
                coordinate.YAxis.Name, this.coordinateYSize, coordinate.YAxis.MaxValue, this.coordinateY, 
                this.coordinateXSize, coordinate.XAxis.MaxValue, this.coordinateX, data[0], data[1],x,y
    );
            }
            return new int[] { x, y };
        }

        /// <summary>
        /// 画
        /// </summary>
        /// <param name="coordinate"></param>
        /// <param name="g"></param>
        private void drawFirstAxis(Coordinate coordinate, Graphics g)
        {
            if (coordinate == null)
            {
                return;
            }
            this.coordinateX = (int)(this.Width * coordinate.LeftRate);
            this.coordinateY = (int)(this.Height * coordinate.BottonRate);
            this.coordinateXSize = (int)(this.Width * coordinate.WidthRate);
            this.coordinateYSize = (int)(this.Height * coordinate.HeightRate);

            double minX = coordinate.XAxis.MinValue;
            double maxX = coordinate.XAxis.MaxValue;

            //画X轴的实线
            int[] pMin = transformsPoint(coordinate, new double[] { minX, 0 });
            int[] pMax = transformsPoint(coordinate, new double[] { maxX, 0 });
            g.DrawLine(coordinate.AxisPen, pMin[0], pMin[1], pMax[0], pMax[1]);

            

            //画X轴的名字
            g.DrawString(coordinate.XAxis.Name, coordinate.DefaultFont, coordinate.AxisDescritionBrush, pMax[0] -20  , pMax[1] + 20 );


            int segCount = coordinate.XAxis.SegCount;

            double unit = (maxX - minX) / coordinate.XAxis.SegCount;

            //画坐标的等分点和基于等分线的辅助虚线。
            for (int i = 1; i <= segCount; i++)
            {
                int[] point = transformsPoint(coordinate, new double[] { minX + i * unit, 0 });

                //画等分点
                g.FillEllipse(coordinate.AuxiliaryAxisPointBrush, point[0] - 2, point[1] - 2, 4, 4);

                g.DrawString(Decimal.Round((decimal)(minX + i * unit), 2).ToString(), coordinate.DefaultFont, coordinate.AxisDescritionBrush, point[0]-5, point[1] + 5 );

                //画等分虚线
                int[] pointX = transformsPoint(coordinate, new double[] { minX + i * unit, 0 });
                int[] pointY = transformsPoint(coordinate, new double[] { minX + i * unit, coordinate.YAxis.MaxValue });


                // pen.DashStyle = System.Drawing.Drawing2D.DashStyle.DashDot;
                g.DrawLine(coordinate.AuxiliaryAxisPen, pointX[0], pointX[1], pointY[0], pointY[1]);
                //pen.DashStyle = System.Drawing.Drawing2D.DashStyle.Dash;
            }


            //画第一坐标系的Y轴
            int[] pMinY = transformsPoint(coordinate, new double[] { 0, coordinate.YAxis.MinValue });
            int[] pMaxY = transformsPoint(coordinate, new double[] { 0, coordinate.YAxis.MaxValue });
            g.DrawLine(coordinate.AxisPen, pMinY[0], pMinY[1], pMaxY[0], pMaxY[1]);

            g.DrawString(coordinate.YAxis.Name, coordinate.DefaultFont, coordinate.AuxiliaryBrush, pMaxY[0] -10, pMaxY[1] - 25);

            segCount = coordinate.YAxis.SegCount;
            unit = (coordinate.YAxis.MaxValue - coordinate.YAxis.MinValue) / coordinate.YAxis.SegCount;

            //画坐标系Y轴的等分点和基于等分线的辅助虚线。
            for (int i = 1; i <= segCount; i++)
            {
                double minY = coordinate.YAxis.MinValue;
                int[] point = transformsPoint(coordinate, new double[] { 0, minY + i * unit });
                g.FillEllipse(coordinate.AuxiliaryAxisPointBrush, point[0] - 2, point[1] - 2, 4, 4);

                g.DrawString( Decimal.Round((decimal) (minY + i * unit),2).ToString(), coordinate.DefaultFont, coordinate.AxisDescritionBrush, point[0] - 30, point[1]);
                int[] pointX = transformsPoint(coordinate, new double[] { 0, minY + i * unit });
                int[] pointY = transformsPoint(coordinate, new double[] { coordinate.XAxis.MaxValue, minY + i * unit });

                g.DrawLine(coordinate.AuxiliaryAxisPen, pointX[0], pointX[1], pointY[0], pointY[1]);
            }

        }

        /// <summary>
        /// 画除了第一坐标系外的坐标系的Y轴
        /// </summary>
        /// <param name="coordinate"></param>
        /// <param name="g"></param>
        /// <param name="offsetRate"></param>
        private void drawOtherAxix(Coordinate coordinate, Graphics g, float offsetRate)
        {
            if (coordinate == null)
            {
                return;
            }
            int yAxisPosition = (int)(this.Width * (coordinate.LeftRate + coordinate.WidthRate + offsetRate));

            int[] pMinY = transformsPoint(coordinate, new double[] { yAxisPosition, coordinate.YAxis.MinValue });
            int[] pMaxY = transformsPoint(coordinate, new double[] { yAxisPosition, coordinate.YAxis.MaxValue });
            //g.DrawLine(pen, pMinY[0], pMinY[1], pMaxY[0], pMaxY[1]);

            g.DrawLine(coordinate.AxisPen, yAxisPosition, pMinY[1], yAxisPosition, pMaxY[1]);

            g.DrawString(coordinate.YAxis.Name, coordinate.DefaultFont, coordinate.AuxiliaryBrush, yAxisPosition-10, pMaxY[1] - 25);

            int segCount = coordinate.YAxis.SegCount;
            double unit = (coordinate.YAxis.MaxValue - coordinate.YAxis.MinValue) / coordinate.YAxis.SegCount;

            for (int i = 1; i <= segCount; i++)
            {
                double minY = coordinate.YAxis.MinValue;
                int[] point = transformsPoint(coordinate, new double[] { yAxisPosition, minY + i * unit });
                g.FillEllipse(coordinate.AuxiliaryAxisPointBrush, yAxisPosition - 2, point[1] - 2, 4, 4);
                g.DrawString(Decimal.Round((decimal)(minY + i * unit), 2).ToString(), coordinate.DefaultFont, coordinate.AxisDescritionBrush, yAxisPosition + 10, point[1] - 8);
            }
        }

        /// <summary>
        /// 画坐标系中的点
        /// </summary>
        /// <param name="coordinate"></param>
        /// <param name="g"></param>
        private void drawPoints(Coordinate coordinate, Graphics g)
        {
            if (coordinate == null)
            {
                return;
            }
            for (int i = 0; i < coordinate.Points.Count; i++)
            {
                int[] point = transformsPoint(coordinate, new double[] { coordinate.Points[i].X, coordinate.Points[i].Y });
                Brush pointBrush;
                if (coordinate.Points[i].Color.Equals(Color.Transparent))
                {
                    pointBrush = coordinate.PointBrush;
                }
                else
                {
                    pointBrush = new SolidBrush(coordinate.Points[i].Color);

                }

                g.FillEllipse(pointBrush, point[0] - 4, point[1] - 4, 8, 8);
            }
        }

        private void drawCurve(Coordinate coordinate, Graphics g)
        {
            if (coordinate == null)
            {
                return;
            }
            for (int i = 0; i < coordinate.Curves.Count; i++)
            {
                Curve curve = coordinate.Curves[i];
                PointF[] pointF = new PointF[curve.Points.Count];
                for (int j = 0; j < curve.Points.Count; j++)
                {
                    int[] point = transformsPoint(coordinate, new double[] { curve.Points[j].X, curve.Points[j].Y });
                    pointF[j].X = (float)point[0];
                    pointF[j].Y = (float)point[1];
                }
                //pen.DashStyle = System.Drawing.Drawing2D.DashStyle.Custom;
                if(pointF.Length>=1)
                {
                    g.DrawCurve(coordinate.CurvePen, pointF);
                }
                

            }
        }

        private void logRectangle(String name,int x,int y,int width,int height)
        {
            System.Console.WriteLine("-----------------{0}----------------",name);
            System.Console.WriteLine("x = {0},y = {1},width = {2},height = {3}",x,y,width,height);
            System.Console.WriteLine("------------------------------------");
        }

        private void drawRectangle(Coordinate coordinate, Graphics g)
        {
            if (coordinate == null)
            {
                return;
            }
            for (int i = 0; i < coordinate.Rectangles.Count; i++)
            {

                RectangleX rectangle = coordinate.Rectangles[i];
                int[] pointStart = transformsPoint(coordinate, new double[]  { (double)rectangle.X, (double)(rectangle.Y) },true);
                int[] pointEnd = transformsPoint(coordinate,   new double[]  { (double)rectangle.X+rectangle.Width, (double)(rectangle.Y) - rectangle.Height });
                int[] widthPoint = transformsPoint(coordinate, new double[]  { (double)rectangle.Width,0 });
                int[] heightPoint = transformsPoint(coordinate, new double[] { 0, (double)rectangle.Height });

                //g.DrawRectangle(coordinate.CurvePen, (float)pointStart[0], (float)pointStart[1], (float)widthPoint[0], (float)heightPoint[1]);
                
               g.DrawRectangle(coordinate.CurvePen, (float)pointStart[0], (float)pointStart[1], (float)(pointEnd[0]- pointStart[0]), (float)(pointEnd[1] - pointStart[1]));
                /* logRectangle(name, pointStart[0], pointStart[1], (pointEnd[0] - pointStart[0]), (pointEnd[1] - pointStart[1]));*/
               

            }

        }

        private void drawCrossRegion(Coordinate coordinate, Graphics g)
        {
            if (coordinate == null)
            {
                return;
            }
            for (int i = 0; i < coordinate.CrossRegion.Count; i++)
            {

                CrossRegion crossRegion = coordinate.CrossRegion[i];

                int[] minXPoint = transformsPoint(coordinate, new double[] { crossRegion.XMin  , crossRegion.Y });
                int[] maxXPoint = transformsPoint(coordinate, new double[] { crossRegion.XMax,   crossRegion.Y });
                int[] minYPoint = transformsPoint(coordinate, new double[] { crossRegion.X,   crossRegion.YMin });
                int[] maxYPoint = transformsPoint(coordinate, new double[] { crossRegion.X, crossRegion.YMax });

                g.DrawLine(new Pen(coordinate.PointBrush,3), minXPoint[0], minXPoint[1], maxXPoint[0], maxXPoint[1]);
                g.DrawLine(new Pen(coordinate.PointBrush,3), minYPoint[0], minYPoint[1], maxYPoint[0], maxYPoint[1]);

            }

        }



        private void drawLines(Coordinate coordinate, Graphics g)
        {
            if (coordinate == null)
            {
                return;
            }
            for (int i = 0; i < coordinate.Lines.Count; i++)
            {
                int[] pointStart = transformsPoint(coordinate,new double[] { coordinate.Lines[i].Start.X, coordinate.Lines[i].Start.Y });
                int[] pointEnd = transformsPoint(coordinate, new double[] { coordinate.Lines[i].End.X, coordinate.Lines[i].End.Y });
                Pen linePen;
                if (coordinate.Lines[i].Color.Equals(Color.Transparent))
                {
                    linePen = coordinate.LinePen;
                }
                else
                {
                    linePen = new Pen(new SolidBrush(coordinate.Lines[i].Color));

                }
                   
                g.DrawLine(linePen, pointStart[0],pointStart[1], pointEnd[0], pointEnd[1]);

            }
        }

       
        private int drawAxis(Graphics g)
        {
            if (firstCoordinate == null)
            {
                return -1;
            }

            double xMaxValue = firstCoordinate.XAxis.MaxValue;
            double xMinValue = firstCoordinate.XAxis.MinValue;

            double y1Max = firstCoordinate.YAxis.MaxValue;
            double y1Min = firstCoordinate.YAxis.MinValue;
            if (Math.Abs(xMinValue - xMaxValue) < 0.0001 || Math.Abs(y1Max - y1Min) < 0.0001)
            {
                return -1;
            }
            drawFirstAxis(firstCoordinate, g);
 

            if (secondCoordinate != null)
            {
                double y2Max = secondCoordinate.YAxis.MaxValue;
                double y2Min = secondCoordinate.YAxis.MinValue;
                if (Math.Abs(y2Max - y2Min) < 0.0001)
                {
                    return -1;
                }
                drawOtherAxix(secondCoordinate, g, 0.03f);
                //drawRectangle(secondCoordinate, g);
            }

            if (thirdCoordinate != null)
            {
                double y3Max = thirdCoordinate.YAxis.MaxValue;
                double y3Min = thirdCoordinate.YAxis.MinValue;
                if (Math.Abs(y3Max - y3Min) < 0.0001)
                {
                    return -1;
                }
                drawOtherAxix(thirdCoordinate, g, 0.10f);
                //drawRectangle(thirdCoordinate, g);
            }       
     
            return 0;

        }

        private void UserChart_Paint(object sender, PaintEventArgs e)
        {
            Graphics graphics = e.Graphics;
            int ret= drawAxis(graphics);
            if (ret != 0)
            {
                return;
            }

            if(firstCoordinate.Points.Count>0)
            { 
                drawPoints(firstCoordinate, graphics);
            }
            if (firstCoordinate.Curves != null && firstCoordinate.Curves.Count != 0)
            {
                drawCurve(firstCoordinate, graphics);
            }
            if (firstCoordinate.Rectangles !=null && this.firstCoordinate.Rectangles.Count!=0)
            {
                this.drawRectangle(firstCoordinate, graphics);
            }
            if (firstCoordinate.Lines != null && this.firstCoordinate.Lines.Count != 0)
            {
                this.drawLines(firstCoordinate, graphics);
            }
            if (firstCoordinate.CrossRegion != null && firstCoordinate.CrossRegion.Count != 0)
            {
                this.drawCrossRegion(firstCoordinate, graphics);
            }


            if (secondCoordinate!=null)
            {
                if (secondCoordinate.Points.Count > 0)
                {
                    drawPoints(secondCoordinate, graphics);
                }
                if (secondCoordinate.Curves != null && secondCoordinate.Curves.Count != 0)
                {
                    drawCurve(secondCoordinate, graphics);
                }
                if (secondCoordinate.Rectangles != null && this.secondCoordinate.Rectangles.Count != 0)
                {
                    this.drawRectangle(secondCoordinate, graphics);
                }
                if (secondCoordinate.Lines != null && this.secondCoordinate.Lines.Count != 0)
                {
                    this.drawLines(secondCoordinate, graphics);
                }
                if (secondCoordinate.CrossRegion != null && secondCoordinate.CrossRegion.Count != 0)
                {
                    this.drawCrossRegion(secondCoordinate, graphics);
                }

            }

            if (thirdCoordinate != null)
            {
                if (thirdCoordinate.Points.Count > 0)
                {

                    drawPoints(thirdCoordinate, graphics);
                }

                if (thirdCoordinate.Curves != null && thirdCoordinate.Curves.Count != 0)
                {
                    drawCurve(thirdCoordinate, graphics);
                }
                if (thirdCoordinate.Rectangles != null && this.thirdCoordinate.Rectangles.Count != 0)
                {
                    this.drawRectangle(thirdCoordinate, graphics);
                }
                if (thirdCoordinate.Lines != null && this.thirdCoordinate.Lines.Count != 0)
                {
                    this.drawLines(thirdCoordinate, graphics);
                }
                if (thirdCoordinate.CrossRegion != null && thirdCoordinate.CrossRegion.Count != 0)
                {
                    this.drawCrossRegion(thirdCoordinate, graphics);
                }
            }
            




        }
    }
}
